<!DOCTYPE html>
<html>
<head>
    <title>Thermodynamics Diagram</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
        }
        canvas {
            border: 1px solid #ccc;
        }
    </style>
</head>
<body>
    <canvas id="physicsCanvas" width="800" height="500"></canvas>
    <script>
        const canvas = document.getElementById('physicsCanvas');
        const ctx = canvas.getContext('2d');

        // Style settings
        ctx.strokeStyle = 'black';
        ctx.fillStyle = 'black';
        ctx.lineWidth = 2;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        // Geometry parameters
        const L = 220;
        const H = 80;
        const l = 15;
        const startX = 150;
        const startY = 150;
        const wallThickness = 15;
        const hatchSpacing = 7;

        // Helper function for hatching
        function drawHatching(x, y, width, height) {
            ctx.save();
            ctx.beginPath();
            ctx.rect(x, y, width, height);
            ctx.clip(); // Clip to the rectangle area

            const oldLineWidth = ctx.lineWidth;
            ctx.lineWidth = 1;
            ctx.strokeStyle = 'black';
            
            for (let i = -height; i < width; i += hatchSpacing) {
                ctx.beginPath();
                ctx.moveTo(x + i, y);
                ctx.lineTo(x + i + height, y + height);
                ctx.stroke();
            }
            ctx.lineWidth = oldLineWidth;
            ctx.restore();
        }

        // Helper function to draw an arrow on a line
        function drawArrow(x1, y1, x2, y2, headLength = 10) {
            const dx = x2 - x1;
            const dy = y2 - y1;
            const angle = Math.atan2(dy, dx);
            ctx.beginPath();
            ctx.moveTo(x1, y1);
            ctx.lineTo(x2, y2);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(x2, y2);
            ctx.lineTo(x2 - headLength * Math.cos(angle - Math.PI / 6), y2 - headLength * Math.sin(angle - Math.PI / 6));
            ctx.moveTo(x2, y2);
            ctx.lineTo(x2 - headLength * Math.cos(angle + Math.PI / 6), y2 - headLength * Math.sin(angle + Math.PI / 6));
            ctx.stroke();
        }

        // --- Main Drawing ---

        // 1. Cylinder walls
        const totalHeight = 2 * H;
        const totalWidth = 2 * L + l;
        const cylinderTopY = startY;
        const cylinderBottomY = startY + totalHeight;
        const cylinderLeftX = startX;
        const cylinderRightX = startX + totalWidth;

        // Top and bottom walls (as part of a larger box)
        ctx.beginPath();
        ctx.rect(cylinderLeftX, cylinderTopY, totalWidth, totalHeight);
        ctx.stroke();
        drawHatching(cylinderLeftX, cylinderTopY-wallThickness, totalWidth, wallThickness);
        drawHatching(cylinderLeftX, cylinderBottomY, totalWidth, wallThickness);
        
        // Left fixed wall (Heat source wall)
        drawHatching(cylinderLeftX - wallThickness, cylinderTopY - wallThickness, wallThickness, totalHeight + 2 * wallThickness);
        ctx.strokeRect(cylinderLeftX - wallThickness, cylinderTopY - wallThickness, wallThickness, totalHeight + 2*wallThickness);


        // 2. Piston
        const pistonX = cylinderLeftX + L;
        ctx.beginPath();
        ctx.rect(pistonX, cylinderTopY, l, totalHeight);
        ctx.fillStyle = 'white'; // To block cylinder lines behind it
        ctx.fill();
        ctx.stroke();
        drawHatching(pistonX, cylinderTopY, l, totalHeight);
        ctx.fillStyle = 'black'; // Reset fill style


        // 3. Left chamber contents
        const waterLineY = startY + H;
        // Water/vapor line
        ctx.beginPath();
        ctx.moveTo(cylinderLeftX, waterLineY);
        ctx.lineTo(pistonX, waterLineY);
        ctx.stroke();
        // Dashed lines for water
        ctx.save();
        ctx.setLineDash([10, 5]);
        const oldLineWidth = ctx.lineWidth;
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.moveTo(cylinderLeftX, waterLineY + H / 3);
        ctx.lineTo(pistonX, waterLineY + H / 3);
        ctx.moveTo(cylinderLeftX, waterLineY + 2 * H / 3);
        ctx.lineTo(pistonX, waterLineY + 2 * H / 3);
        ctx.stroke();
        ctx.lineWidth = oldLineWidth;
        ctx.restore();

        // 4. Right chamber coil
        const coilTermX = cylinderRightX + 20;
        const coilYTop = startY + H - 25;
        const coilYBottom = startY + H + 25;

        ctx.beginPath();
        ctx.moveTo(cylinderRightX, coilYTop);
        ctx.lineTo(coilTermX, coilYTop);
        ctx.moveTo(cylinderRightX, coilYBottom);
        ctx.lineTo(coilTermX, coilYBottom);

        const numLoops = 3;
        const yStep = (coilYBottom - coilYTop) / numLoops;
        ctx.moveTo(coilTermX, coilYTop);
        for (let i = 0; i < numLoops; i++) {
            ctx.arc(coilTermX, coilYTop + i * yStep + yStep / 2, yStep / 2, Math.PI, 0, false);
        }
        ctx.stroke();

        
        // 5. Dimension lines and labels
        const oldLineWidthDim = ctx.lineWidth;
        ctx.lineWidth = 1;
        const dimOffsetY = 30;
        const dimOffsetX = 40;

        // L (left)
        let y_dim = cylinderTopY - dimOffsetY;
        drawArrow(cylinderLeftX, y_dim, pistonX, y_dim);
        drawArrow(pistonX, y_dim, cylinderLeftX, y_dim);
        ctx.beginPath();
        ctx.moveTo(cylinderLeftX, y_dim - 5); ctx.lineTo(cylinderLeftX, y_dim + 5);
        ctx.moveTo(pistonX, y_dim - 5); ctx.lineTo(pistonX, y_dim + 5);
        ctx.stroke();
        ctx.font = 'italic 22px "Times New Roman"';
        ctx.fillText('L', cylinderLeftX + L / 2, y_dim - 15);
        
        // L (right)
        drawArrow(pistonX + l, y_dim, cylinderRightX, y_dim);
        drawArrow(cylinderRightX, y_dim, pistonX + l, y_dim);
        ctx.beginPath();
        ctx.moveTo(pistonX + l, y_dim - 5); ctx.lineTo(pistonX + l, y_dim + 5);
        ctx.moveTo(cylinderRightX, y_dim - 5); ctx.lineTo(cylinderRightX, y_dim + 5);
        ctx.stroke();
        ctx.fillText('L', pistonX + l + L / 2, y_dim - 15);
        
        // H (vapor)
        let x_dim = pistonX + l + dimOffsetX;
        drawArrow(x_dim, waterLineY, x_dim, cylinderTopY);
        drawArrow(x_dim, cylinderTopY, x_dim, waterLineY);
        ctx.beginPath();
        ctx.moveTo(x_dim - 5, cylinderTopY); ctx.lineTo(x_dim + 5, cylinderTopY);
        ctx.moveTo(x_dim - 5, waterLineY); ctx.lineTo(x_dim + 5, waterLineY);
        ctx.stroke();
        ctx.fillText('H', x_dim + 20, cylinderTopY + H / 2);

        // H (water)
        drawArrow(x_dim, cylinderBottomY, x_dim, waterLineY);
        drawArrow(x_dim, waterLineY, x_dim, cylinderBottomY);
        ctx.beginPath();
        ctx.moveTo(x_dim - 5, waterLineY); ctx.lineTo(x_dim + 5, waterLineY);
        ctx.moveTo(x_dim - 5, cylinderBottomY); ctx.lineTo(x_dim + 5, cylinderBottomY);
        ctx.stroke();
        ctx.fillText('H', x_dim + 20, waterLineY + H / 2);

        // l (piston thickness)
        y_dim = cylinderBottomY + dimOffsetY;
        drawArrow(pistonX, y_dim, pistonX + l, y_dim);
        drawArrow(pistonX + l, y_dim, pistonX, y_dim);
        ctx.beginPath();
        ctx.moveTo(pistonX, y_dim - 5); ctx.lineTo(pistonX, y_dim + 5);
        ctx.moveTo(pistonX + l, y_dim - 5); ctx.lineTo(pistonX + l, y_dim + 5);
        ctx.stroke();
        ctx.fillText('l', pistonX + l/2, y_dim + 15);
        
        ctx.lineWidth = oldLineWidthDim;

        // 6. Text labels
        
        // S labels
        ctx.font = 'italic 24px "Times New Roman"';
        ctx.fillText('S', cylinderLeftX + 25, waterLineY - H / 2);
        ctx.fillText('S', pistonX + l + 25, waterLineY - H / 2);

        // Left chamber
        ctx.font = '28px "SimSun", "STSong"';
        ctx.fillText('汽', cylinderLeftX + L / 2, cylinderTopY + 30);
        ctx.fillText('水', cylinderLeftX + L / 2, waterLineY + 40);
        
        ctx.font = 'italic 22px "Times New Roman"';
        ctx.fillText('p', cylinderLeftX + L/2 - 25, waterLineY - 30);
        ctx.font = '16px "Times New Roman"';
        ctx.fillText('0', cylinderLeftX + L/2 - 25 + 10, waterLineY - 30 + 5);
        ctx.font = 'italic 22px "Times New Roman"';
        ctx.fillText('T', cylinderLeftX + L/2 + 25, waterLineY - 30);
        ctx.font = '16px "Times New Roman"';
        ctx.fillText('0', cylinderLeftX + L/2 + 25 + 12, waterLineY - 30 + 5);

        // Right chamber
        const rightChamberCenterX = pistonX + l + L / 2;
        ctx.font = 'italic 22px "Times New Roman"';
        ctx.fillText('p', rightChamberCenterX, startY + 50);
        ctx.font = '16px "Times New Roman"';
        ctx.fillText('i', rightChamberCenterX + 8, startY + 50 + 5);

        ctx.font = 'italic 22px "Times New Roman"';
        ctx.fillText('T', rightChamberCenterX, startY + H + 40);
        ctx.font = '16px "Times New Roman"';
        ctx.fillText('i', rightChamberCenterX + 10, startY + H + 40 + 5);

        // Heat source label
        const heatSourceX = cylinderLeftX - wallThickness - 30;
        ctx.font = 'italic 24px "Times New Roman"';
        ctx.fillText('T', heatSourceX, startY + 20);
        ctx.font = '18px "Times New Roman"';
        ctx.fillText('0', heatSourceX + 12, startY + 20 + 5);
        ctx.font = '24px "SimSun", "STSong"';
        ctx.fillText('大', heatSourceX, startY + 55);
        ctx.fillText('热', heatSourceX, startY + 85);
        ctx.fillText('源', heatSourceX, startY + 115);

    </script>
</body>
</html>